// Copyright 2010 Google Inc. All Rights Reserved.

/**
 * @fileoverview Config.
 *
 * @author monsur@google.com (Monsur Hossain)
 */

goog.provide('googleapis.Config');


/**
 * Stores configuration data related to the googleapis classes.  Allows
 * developers to override values using global variables or local storage.
 * @constructor
 */
googleapis.Config = function() {
};


/**
 * @type {string} Standard prefix for cookie configuration
 */
googleapis.Config.PREFIX = 'googleapis';


/**
 * @type {string} Connect config window variable and local storage name
 */
googleapis.Config.KEY = '__GOOGLEAPIS';


/**
 * @type {string} Cookie name.
 * Cookies on .google.com get cleared by GWS and we need a cookie that doesn't
 * get cleared. To unblock dev, we are using "MPRF".
 * TODO(uidude) Get our own cookie.
 */
googleapis.Config.COOKIE_NAME = 'MPRF';


/**
 * Get a config value from a cookie if it exists.
 * @param {string} configKey The config key.
 * @return {?string} The value.
 * @private
 */
googleapis.Config.getCookieConfigValue_ = function(configKey) {
  var cookie = goog.net.cookies.get(googleapis.Config.COOKIE_NAME);
  if (cookie) {
    var keyValuePairs = cookie.split('|');
    for (var i = 0; i < keyValuePairs.length; i++) {
      var equalPos = keyValuePairs[i].indexOf('=');
      var key = keyValuePairs[i].substring(0, equalPos);
      var value = keyValuePairs[i].substring(equalPos + 1);
      if (key == googleapis.Config.PREFIX + '.' + configKey) {
        return value;
      }
    }
  }
  return null;
};


/**
 * Set a config value in a cookie.
 * @param {string} key The config key.
 * @param {string} value The value.
 * @private
 */
googleapis.Config.setConfigCookieValue_ = function(key, value) {
  var cookieKey = googleapis.Config.PREFIX + '.' + key;
  var cookie = goog.net.cookies.get(googleapis.Config.COOKIE_NAME);
  var result = [];
  if (cookie) {
    var keyValuePairs = cookie.split('|');
    for (var i = 0; i < keyValuePairs.length; i++) {
      if (keyValuePairs[i].indexOf(cookieKey) != 0) {
        result.push(keyValuePairs[i]);
      }
    }
  }
  result.push(cookieKey + '=' + value);
  goog.net.cookies.set(googleapis.Config.COOKIE_NAME, result.join('|'), 3600000,
      '/', 'google.com');
};


/**
 * Override JSON fields in an object with JSON fields in another object.
 * @param {Object} target The target.
 * @param {Object} src The source.
 * @private
 */
googleapis.Config.override_ = function(target, src) {
  for (var key in src) {
    var value = src[key];
    if (typeof value === 'object' && value != null) {
      if (typeof target == 'object') {
        if (!target[key]) {
          target[key] = {};
        }
        googleapis.Config.override_(target[key], value);
      } else if (typeof target == 'boolean') {
        googleapis.Config.override_(target, value);
      }
    } else {
      if (typeof target == 'object') {
        target[key] = value;
      } else {
        target = value;
      }
    }
  }
};


/**
 * Get configuration - order is:
 * - Base is configured in JS
 * - Override based on JS variable window['__GOOGLEAPIS'],
 *     declared before loading config
 * - Override with cookie. This is only in for backwards compatibility
 *     and will be going away.
 * - Override with local storage. This is for developers only
 * @return {Object} The JSON configuration.
 * @private
 */
googleapis.Config.getConfig_ = function() {
  // TODO(uidude) Cache results
  var config = gadgets.config.get();
  if (window[googleapis.Config.KEY]) {
    googleapis.Config.override_(config, window[googleapis.Config.KEY]);
  }
  // TODO(xiangtian): switch to use googleapis.BrowserStorage.
  var localData;
  try {
    // Firefox throws a security exception when trying to access properties
    // of localStorage if it is not allowed.
    localData = window.localStorage &&
        window.localStorage[googleapis.Config.KEY];
  } catch (e) {
    // Nothing need to be done in this case, just ignore it.
  }
  if (localData) {
    googleapis.Config.override_(config, gadgets.json.parse(localData));
  }
  var deprecatedCookieKeys = ['proxy', 'rpc'];
  for (var i = 0; i < deprecatedCookieKeys.length; i++) {
    var key = deprecatedCookieKeys[i];
    var cookieValue = googleapis.Config.getCookieConfigValue_(key);
    if (cookieValue) {
      config[googleapis.Config.PREFIX][key] = cookieValue;
    }
  }
  return config;
};


/**
 * Get the configuration for a specific feature.
 * @param {string} feature The name of the feature.
 * @return {Object} The JSON config.
 */
googleapis.Config.getFeatureConfig = function(feature) {
  return googleapis.Config.getConfig_()[feature];
};

/**
 * Get the config for googleapis.
 * @return {Object} The JSON config.
 */
googleapis.Config.get = function() {
  return googleapis.Config.getFeatureConfig(googleapis.Config.PREFIX) || {};
};


/**
 * Returns the config value at the specified location.  If the value doesn't
 * exist, returns null.  For example, suppose the config has the following
 * structure: {"a": {"b": 1234}}.  Calling Config.getValue("a.b") will
 * return 1234.  Calling Config.getValue("a") will return {"b": 1234}.
 * Calling Config.getValue("b.c") will return null.
 * @param {string|Array.<string>} fullKey The key of the config value,
 *     specified as either a string or an array (for example: "a.b.c" or
 *     ["a", "b", "c"].  Use an array for key names with periods in them.
 * @return {*} The config value at the specified location.
 */
googleapis.Config.getValue = function(fullKey) {
  if (!fullKey) {
    return null;
  }
  var pieces = fullKey;
  if (typeof fullKey === 'string') {
    pieces = fullKey.split('.');
  }
  var config = googleapis.Config.get();
  for (var i = 0; i < pieces.length; i++) {
    if (typeof config !== 'object') {
      config = null;
      break;
    }
    var key = pieces[i];
    if (key in config) {
      config = config[key];
    } else {
      config = null;
      break;
    }
  }
  return config;
};


/**
 * Configure the APIs, optionally setting a cookie.
 * @param {Object} params Configuration params.
 * @param {boolean} opt_sticky If true, will set a cookie to remember
 *     the settings.
 */
googleapis.Config.configure = function(params, opt_sticky) {
  for (var key in params) {
    window[googleapis.Config.KEY] = window[googleapis.Config.KEY] || {};
    googleapis.Config.override_(window[googleapis.Config.KEY], params);
    if (opt_sticky) {
      googleapis.Config.setConfigCookieValue_(key, params[key]);
    }
  }
};


/**
 * Clears the configuration cookie.
 */
googleapis.Config.clearConfig = function() {
  goog.net.cookies.remove(googleapis.Config.COOKIE_NAME, '/', 'google.com');
};
